package com.lb.bs.client.processor.handle.statics.first;

import com.lb.bs.client.annotation.LBClass;
import com.lb.bs.client.annotation.LBItem;
import com.lb.bs.client.annotation.ProcessorMark;
import com.lb.bs.client.annotation.SingletonMark;
import com.lb.bs.client.beans.GroupInfo;
import com.lb.bs.client.beans.LBItemBean;
import com.lb.bs.client.repository.ScanStaticModel;
import com.lb.bs.client.repository.BeanHolder;
import com.lb.bs.client.repository.StoreCenter;
import com.lb.bs.client.processor.ProcessorService;
import com.lb.bs.client.processor.enums.ProcessorType;
import com.lb.bs.client.util.FieldUtil;
import com.lb.bs.client.util.KeyGenerateUtil;
import com.lb.bs.client.util.MethodUtil;
import com.lb.bs.client.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * program: LB-BS-Client
 * author: bsworld.xie
 * create: 2019-12-11 16:32
 * description:
 */
@SingletonMark
@ProcessorMark(type = ProcessorType.FIRST_TO_ITEM_BEAN)
public class StaticTransform2ItemBeanProcessor implements ProcessorService<ScanStaticModel> {
    private static final Logger logger = LoggerFactory.getLogger(StaticTransform2ItemBeanProcessor.class);


    @Override
    public void process(ScanStaticModel scanStaticModel) {
        Map<Class<?>, List<Method>> classMethodMap = scanStaticModel.getClazzMethodMap();
        for (Map.Entry<Class<?>, List<Method>> entry : classMethodMap.entrySet()) {
            Class<?> clazz = entry.getKey();
            Object originBean = BeanHolder.getHolder().getBean(clazz);
            if (originBean == null) {
                scanStaticModel.getClazzList().remove(clazz);
                classMethodMap.remove(clazz);
                continue;
            }

            LBClass[] lbClasses = clazz.getAnnotationsByType(LBClass.class);
            if (lbClasses == null || lbClasses.length == 0) {
                continue;
            }

            LBClass lbClass = lbClasses[0];
            String groupName = lbClass.groupName();
            if (StringUtils.isEmpty(groupName)) {
                continue;
            }

            List<Method> methods = classMethodMap.get(clazz);
            for (Method method : methods) {
                LBItem lbItem = method.getAnnotation(LBItem.class);
                String fieldAnnotationKey = lbItem.key();
                Field[] declaredFields = clazz.getDeclaredFields();
                Field field = MethodUtil.getFieldByMethod(method, declaredFields, lbItem.associateField());
                if (field == null) {
                    continue;
                }
                if (StringUtils.isEmpty(fieldAnnotationKey)) {
                    continue;
                }
                String itemKey = KeyGenerateUtil.spliceItemKey(groupName, fieldAnnotationKey);
                LBItemBean itemBean = new LBItemBean();
                itemBean.setField(field);
                itemBean.setItemKey(itemKey);
                itemBean.setMethod(method);
                itemBean.setOriginBean(originBean);
                itemBean.setValue(FieldUtil.transform(field, lbItem.value()));
                itemBean.setEnable(false);
                logger.debug("StaticTransform2ItemBeanProcessor.class, process(),bean:{}",itemBean.getValue() != null ? itemBean.getValue().getClass() : null);
                field.setAccessible(true);
                itemBean.setGroupName(groupName);
                itemBean.setFieldAnnotationKey(fieldAnnotationKey);
                LBItemBean preItemBean = StoreCenter.getInstance().getItemKeyMap().putIfAbsent(itemKey, itemBean);
                if (preItemBean != null) {
                    throw new IllegalStateException("重复配置节点,key:" + itemKey + ", clazz:" + clazz + ", preClazz:"
                            + (preItemBean.getOriginBean() != null ? preItemBean.getOriginBean().getClass() : null));
                }
            }
        }
        Map<String, GroupInfo> groupInfoMap = scanStaticModel.getGroupInfoMap();

        StoreCenter.getInstance().setGroupInfoMap(groupInfoMap);
    }
}
